<?php

namespace Plugins\AdminBasic\Http\Admin\Service\MakeCURDFiles;

use Plugins\AdminBasic\Http\Admin\Service\MakeCURDService;
use Hyperf\Stringable\Str;
use Sc\Util\ScTool;
use Sc\Util\Tool;

/**
 * Class MakeView
 */
class MakeView extends AbstractMake
{
    private array $makeRes = [];

    public function make(): string
    {
        if (in_array('lists', $this->controllerMethod)) {
            $this->makeRes[] = "View lists:" . $this->viewListsMake();
        }

        if (array_intersect($this->controllerMethod, ['create', 'edit'])) {
            $this->makeRes[] = "View create:" . $this->viewCreateMake();
        }

        return '';
    }

    public function getMakeRes(): array
    {
        return $this->makeRes;
    }

    private function viewListsMake(): string
    {
        $use = [];
        $columns = $this->getTableColumns($use);

        $replaceVar = [
            "use"         => implode("\n", array_unique($use)),
            'columns'     => implode("\n    ", $columns),
            "windowWidth" => $this->windowWidth,
        ];

        $filename = preg_replace('/\/+/', '/', $this->dir . '/' . $this->commonReplaceVar['name'] . '/lists');
        $filename = sprintf(MakeCURDService::getTemplate($this->baseFileDir['View'], $this->plugins), $filename);

        $fileContent = file_get_contents(MakeCURDService::TEMPLATE_DIR . 'ViewLists');
        foreach ($this->controllerMethod as $method) {
            $fileContent = preg_replace("/\{\{@ $method }}(.*?)\{\{ $method @}}\s*/s", "$1", $fileContent);
        }
        $fileContent = preg_replace("/\{\{@ $this->windowType }}(.*?)\{\{ $this->windowType @}}\s*/s", "$1", $fileContent);
        $fileContent = preg_replace("/\{\{@ (?<s>[\w-]+) }}(.*?)\{\{ \k<s> @}}\s*/s", "", $fileContent);

        $fileContent = $this->varHandle($replaceVar, $fileContent);

        return $this->makeFile($filename, $fileContent);
    }

    /**
     * @return string
     * @throws \Exception
     */
    private function viewCreateMake(): string
    {
        $use = [];
        $forms = $this->getForms($use);

        $replaceVar = [
            "use"               => implode("\n", array_unique($use)),
            'forms'             => implode("\n    ", $forms),
            'parent'            => $this->windowType === 'iframe' ? 'parent.' : '',
            'successHandlePage' => $this->windowType === 'iframe' ? 'parent' : 'current'
        ];

        $filename = preg_replace('/\/+/', '/', $this->dir . '/' . $this->commonReplaceVar['name'] . '/form');
        $filename = sprintf(MakeCURDService::getTemplate($this->baseFileDir['View'], $this->plugins), $filename);

        $fileContent = file_get_contents(MakeCURDService::TEMPLATE_DIR . 'ViewForm');
        $fileContent = $this->varHandle($replaceVar, $fileContent);
        $fileContent = preg_replace("/\{\{@ $this->windowType }}(.*?)\{\{ $this->windowType @}}\s*/s", "$1", $fileContent);
        $fileContent = preg_replace("/\{\{@ (?<s>[\w-]+) }}(.*?)\{\{ \k<s> @}}\s*/s", "", $fileContent);

        return $this->makeFile($filename, $fileContent);
    }

    /**
     * @param       $use
     *
     * @return array
     */
    private function getTableColumns(&$use): array
    {
        $listsFields = array_filter($this->fields, fn($v) => !empty($v['lists_type']));

        $columns = [];
        foreach ($listsFields as $field) {
            $column = sprintf("Table\Column::normal('%s', '%s')", $field['comment'], $field['field']);

            if (in_array($field['lists_type'], ['tag', 'switch']) && !empty($field['status_map'])) {
                $enumName     = Str::studly($this->table . ' Enum ' . ucfirst($field['field']));
                $enumFilename = sprintf(MakeCURDService::getTemplate($this->baseFileDir['Enum'], $this->plugins), preg_replace('/\/+/', '/', $this->dir . '/' . $enumName));
                if (file_exists($enumFilename)) {
                    $use[] = "use {$this->commonReplaceVar['base_namespace']}\\Enums{$this->commonReplaceVar['dir_namespace']}\\$enumName;";
                    $column .= $field['lists_type'] === 'tag'
                        ? "->showTags($enumName::tagsMapping())"
                        : "->showSwitch($enumName::mapping(),  sc_route([{$this->commonReplaceVar['name']}Controller::class, 'switchToggle']))";
                }elseif (MakeEnum::fieldIsBoolean($field['status_map'])){
                    $use[] = "use App\\Enums\\Booleans;";
                    $column .= $field['lists_type'] === 'tag'
                        ? "->showTags(Booleans::tagsMapping())"
                        : "->showSwitch(Booleans::mapping(),  sc_route([{$this->commonReplaceVar['name']}Controller::class, 'switchToggle']))";
                }
            } elseif ($field['lists_type'] === 'image') {
                $column .= '->showImage()';
            }

            $columns[] = $column . ',';
        }

        return $columns;
    }

    /**
     * @param $use
     *
     * @return array
     * @throws \Exception
     */
    private function getForms(&$use): array
    {
        $listsFields = array_filter($this->fields, fn($v) => !empty($v['form_type']));

        $forms = [];
        foreach ($listsFields as $field) {
            $formType = $field['form_type'];
            if ($formType === 'image') $formType = 'upload';

            $column = sprintf("FormItem::%s('%s', '%s')", $formType, $field['field'], $field['comment']);
            $use[] = "use App\\Http\\Admin\\Controller\\CommonController;";
            if ($formType === 'upload') {
                $column .= "->setUploadUrl(sc_route([CommonController::class, 'upload']))";
            } elseif ($formType === 'editor') {
                $column .= "->setUploadUrl(sc_route([CommonController::class, 'froalaUpload']))";
            }

            if ($field['form_type'] === 'image') {
                $column .= '->toImage()';
            }

            if (!empty($field['status_map'])) {
                $enumName     = Str::studly($this->table . ' Enum ' . $field['field']);
                $baseEnumName = preg_replace('/\/+/', '/', $this->dir . '/' . $enumName);
                if (file_exists(sprintf(MakeCURDService::getTemplate($this->baseFileDir['Enum'], $this->plugins), $baseEnumName))) {
                    $use[] = "use {$this->commonReplaceVar['base_namespace']}\\Enums{$this->commonReplaceVar['dir_namespace']}\\$enumName;";
                    $column .= "->options($enumName::formOptions())";
                }elseif (MakeEnum::fieldIsBoolean($field['status_map'])){
                    $use[] = "use App\\Enums\\Booleans;";
                    $column .= "->options(Booleans::formOptions())";
                }
            }

            if (!empty($field['join_field']) && $formType === 'select') {
                if ($model = $this->getModelByTable($field['join_field']['table'])) {
                    $column .= "->options($model::getSelectData('{$field['join_field']['label']}', '{$field['join_field']['key']}'))";
                }
            }

            $forms[] = $column . ',';
        }
        return $forms;
    }

    /**
     * @param string $table
     *
     * @return string|null
     * @throws \Exception
     */
    private function getModelByTable(string $table): ?string
    {
        $baseDir       = $this->plugins ? BASE_PATH . '/plugins' : BASE_PATH . '/app/Models';
        $baseNamespace = $this->plugins ? ["Plugins"] : ['App', 'Models'];
        $model = null;
        ScTool::dir($baseDir)->each(function (Tool\Dir\EachFile $file) use ($baseNamespace, $table, &$model){
            if (! str_ends_with($file->filename, '.php') ) {
                return;
            }
            $classname = strtr($file->filename, ['.php' => '']);
            $classname = implode('\\', array_merge($baseNamespace, $file->relativelyDirs, [$classname]));
            if ($classname !== "App\\Models\\Model" && class_exists($classname) && method_exists($classname, 'table')) {
                if (forward_static_call([$classname, 'table']) === $table) {
                    $model = $classname;
                    $file->stopEach();
                }
            }
        });

        return $model;
    }

}